package org.geektimes.http.server.jdk.servlet;

import org.geektimes.commons.reflect.util.ClassUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;

import java.util.function.Consumer;
import java.util.logging.Logger;

/**
 * @author wenl
 */
public class FindSuperClassUtils {
    private static final Logger logger = Logger.getLogger( FindSuperClassUtils.class.getName() );
    public static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";

    /**
     * 利用Spring的能力，查找指定类的子类，并忽略制定了，找到后消费掉
     *
     * @param targetClass 指定的父类
     * @param ignoreClass 忽略的子类
     * @param consumer    消费函数
     * @param <T>         指定的类型
     */
    public static <T> void findSubClassAndConsume( Class<T> targetClass, Class<? extends T> ignoreClass, Consumer<Class> consumer ) {
        String packageName = org.springframework.util.ClassUtils.getPackageName( SimpleServletWebServer.class );
        String packagePath = org.springframework.util.ClassUtils.convertClassNameToResourcePath( packageName );
        //classpath*:org/geektimes/http/server/jdk/servlet/**/*.class
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + packagePath + '/' + DEFAULT_RESOURCE_PATTERN;
        PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
        try {
            Resource[] resources = pathMatchingResourcePatternResolver.getResources( packageSearchPath );
            SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
            ClassLoader classLoader = SimpleServletWebServer.class.getClassLoader();
            for ( Resource resource : resources ) {
                MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader( resource );

                String servletClassName = metadataReader.getAnnotationMetadata().getClassName();
                Class clazz = classLoader.loadClass( servletClassName );
                if ( ClassUtils.isAssignableFrom( targetClass, clazz ) && (ignoreClass == null || ignoreClass != clazz) ) {
                    consumer.accept( clazz );
                }
            }
        } catch ( Throwable throwable ) {
            logger.info( String.format( "findSubClassAndConsume has error :%s", throwable.fillInStackTrace() ) );
        }
    }
}
